package com.aiyige.utils;

import android.os.AsyncTask;

import com.aiyige.R;
import com.aiyige.base.api.ApiManager;
import com.aiyige.base.api.ResponseCode;
import com.aiyige.configs.MyConfig;
import com.aiyige.model.Oss;
import com.aiyige.model.response.GetQiniuDomainResponse;
import com.aiyige.model.response.GetQiniuTokenResponse;
import com.aiyige.page.publish.util.PublishUtil;
import com.alibaba.fastjson.JSON;
import com.qiniu.android.common.AutoZone;
import com.qiniu.android.http.ResponseInfo;
import com.qiniu.android.storage.Configuration;
import com.qiniu.android.storage.KeyGenerator;
import com.qiniu.android.storage.UpCancellationSignal;
import com.qiniu.android.storage.UpCompletionHandler;
import com.qiniu.android.storage.UpProgressHandler;
import com.qiniu.android.storage.UploadManager;
import com.qiniu.android.storage.UploadOptions;
import com.qiniu.android.storage.persistent.FileRecorder;

import org.json.JSONObject;

import java.io.File;
import java.util.List;

import okhttp3.ResponseBody;
import retrofit2.Response;

/**
 * Created by zhuyakun on 2017/12/22.
 */

public class UploadPhotoUtil {
    public static final int UPLOAD_STATE_UPLOADING = 1;
    public static final int UPLOAD_STATE_FINISH = 2;
    public static final int UPLOAD_STATE_FAIL = 3;
    public static final long UPLOAD_TIMEOUT_MS = 5000;
    public static final long SCAN_INTERVAL_MS = 500;
    public static final int MAX_RETRY_COUNT = 3;
    Listener listener;
    String photoLocalUrl;
    UploadManager uploadManager;
    AsyncTask<Object, Object, Object> uploadTask;
    String storeKey;
    volatile double uploadPercent;
    volatile long uploadTimestamp;
    volatile boolean cancel;
    volatile int uploadState;
    volatile int retryCount;


    private UploadPhotoUtil(Builder builder) {
        setListener(builder.listener);
        setPhotoLocalUrl(builder.photoLocalUrl);
        storeKey = PublishUtil.generatePhotoFileStoreKey(builder.photoLocalUrl);
        uploadPercent = 0;
        uploadTimestamp = 0;
        retryCount = 0;
        cancel = false;
        uploadState = UPLOAD_STATE_UPLOADING;
        uploadTask = new AsyncTask<Object, Object, Object>() {
            @Override
            protected void onPreExecute() {
                listener.onPreUpload();
            }

            @Override
            protected void onProgressUpdate(Object... values) {
                listener.onProgress((double) values[0]);
            }

            @Override
            protected Object doInBackground(Object... objects) {
                try {
                    while (true) {
                        if (cancel) {
                            uploadState = UPLOAD_STATE_FAIL;
                            return new Exception(StringUtils.getString(R.string.upload_canceled));
                        }
                        switch (uploadState) {
                            case UPLOAD_STATE_UPLOADING: {
                                if (System.currentTimeMillis() - uploadTimestamp > UPLOAD_TIMEOUT_MS) {
                                    if (retryCount < MAX_RETRY_COUNT) {
                                        retryUpload();
                                        uploadTimestamp = System.currentTimeMillis();
                                        retryCount++;
                                    } else {
                                        uploadState = UPLOAD_STATE_FAIL;
                                        return new Exception(StringUtils.getString(R.string.upload_failed));
                                    }
                                }
                                publishProgress(uploadPercent);
                                break;
                            }
                            case UPLOAD_STATE_FINISH: {
                                Response<ResponseBody> response = ApiManager.getService().oss().execute();
                                if (response.code() != ResponseCode.OK) {
                                    throw new Exception(ErrorUtil.extractMessageFromErrorResponse(response));
                                }
                                String json = RetrofitUtil.getResponseBodyAsString(response);
                                List<Oss> ossList = JSON.parseArray(json, Oss.class);
                                if (ListUtil.isEmpty(ossList)) {
                                    throw new Exception("OSS列表为空");
                                }
                                Oss oss = ossList.get(0);
                                String photoDomain = oss.getImage().getDomain() + "/";
                                return photoDomain + storeKey;
                            }
                        }
                        Thread.sleep(SCAN_INTERVAL_MS);
                    }
                } catch (Exception e) {
                    return e;
                }
            }

            @Override
            protected void onPostExecute(Object o) {
                if (o instanceof Exception) {
                    listener.onFail((Throwable) o);
                } else {
                    listener.onFinish((String) o);
                }
            }

            public void retryUpload() throws Exception {
                Response<ResponseBody> response = ApiManager.getService().oss().execute();
                if (response.code() != ResponseCode.OK) {
                    throw new Exception(ErrorUtil.extractMessageFromErrorResponse(response));
                }
                String json = RetrofitUtil.getResponseBodyAsString(response);
                List<Oss> ossList = JSON.parseArray(json, Oss.class);
                if (ListUtil.isEmpty(ossList)) {
                    throw new Exception("OSS列表为空");
                }
                Oss oss = ossList.get(0);
                String photoToken = oss.getImage().getToken().getToken();
                FileRecorder recorder = new FileRecorder(MyConfig.QINIU_UPLOAD_CACHE_DIR);
                KeyGenerator keyGen = new KeyGenerator() {
                    public String gen(String key, File file) {
                        return key + "_._" + new StringBuffer(file.getAbsolutePath()).reverse();
                    }
                };
                Configuration configuration = new Configuration.Builder()
                        .chunkSize(512 * 1024)
                        .putThreshhold(1024 * 1024)
                        .connectTimeout(10)
                        .responseTimeout(15)
                        .recorder(recorder, keyGen)
                        .zone(AutoZone.autoZone)
                        .build();
                uploadManager = new UploadManager(configuration);

                UploadOptions uploadOptions = new UploadOptions(
                        null,
                        null,
                        false,
                        new UpProgressHandler() {
                            @Override
                            public void progress(String key, double percent) {
                                uploadTimestamp = System.currentTimeMillis();
                                uploadPercent = percent;
                            }
                        },
                        new UpCancellationSignal() {
                            @Override
                            public boolean isCancelled() {
                                return uploadState == UPLOAD_STATE_FAIL;
                            }
                        });

                UpCompletionHandler upCompletionHandler = new UpCompletionHandler() {
                    @Override
                    public void complete(String key, ResponseInfo info, JSONObject response) {
                        if (info.isOK()) {
                            uploadState = UPLOAD_STATE_FINISH;
                        }
                    }
                };
                uploadManager.put(
                        photoLocalUrl,
                        storeKey,
                        photoToken,
                        upCompletionHandler,
                        uploadOptions);
            }
        };
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public Listener getListener() {
        return listener;
    }

    public void setListener(Listener listener) {
        this.listener = listener;
    }

    public String getPhotoLocalUrl() {
        return photoLocalUrl;
    }

    public void setPhotoLocalUrl(String photoLocalUrl) {
        this.photoLocalUrl = photoLocalUrl;
    }


    public interface Listener {
        void onPreUpload();

        void onProgress(double progress);

        void onFail(Throwable t);

        void onFinish(String url);
    }

    public static final class Builder {
        private Listener listener;
        private String photoLocalUrl;

        private Builder() {
        }

        public Builder listener(Listener listener) {
            this.listener = listener;
            return this;
        }

        public Builder photoLocalUrl(String photoLocalUrl) {
            this.photoLocalUrl = photoLocalUrl;
            return this;
        }

        public UploadPhotoUtil build() {
            return new UploadPhotoUtil(this);
        }
    }

    public void upload() {
        uploadTask.execute();
    }

    public void cancelUpload() {
        cancel = true;
    }
}
